﻿#define _CRT_SECURE_NO_WARNINGS
#define _WINSOCK_DEPRECATED_NO_WARNINGS


#include <WinSock2.h>
#include <iostream>
#include<time.h>
#include<vector>
#include<fstream>
#include <thread>
#include <mutex>
using namespace std;
#define PORT_SERVER 6656    //自定义端口6666
#define NUM_CLIENTS 10
#define CHECK_DURATION 10000

#pragma comment(lib,"ws2_32.lib")
struct user_list//存储用户信息
{
	char sq_pid[13];
	int report;
	int time = 0;
};
struct sq_list//存储序列号信息
{
	char sq[11];
	int rest;//剩余可用序列号
	
};
struct purchase_list//购买人信息
{
	char name[12] = { 0 };
	char pass[12] = { 0 };
	char type;
	char sq[12];

};
vector<sq_list> sq_db;
vector<user_list>user_db;

int task1();	//监听，周期判崩
int task2();	//主功能
char* randstr(char*& str, const int len);	//生成序列号
void purchase(SOCKET sock_client);			//购买序列号并返回
void save();		//记录序列号
void save_user();	//记录pid，即拓展序列号
int compare(vector<sq_list>& a, char* sq, int type);
void confirm(SOCKET sock_client);			//检查序列号
void usage(SOCKET sock_client);				//使用软件
void setup();		//读取已保存的序列号、pid到list中
bool compare(vector<user_list>& a, char* sq, int type);	
//遍历a中的user_list,匹配命中则在相应report++，然后返回true

int main()
{
	void setup();
	//主功能；
	int task2();
	//崩溃监听功能
	int task1();
	setup();
	thread t2(task2);
	Sleep(10000);
	thread t1(task1);
	t2.join();
	
	t1.join();
}
int task1()
{
	int compare(vector<sq_list> & a, char* sq, int type);
	void save_user();
	void save();
	int flag = 0;
	while (true)
	{
		Sleep(20000);
		// 设置崩溃检测时间为服务器端发送确认时间的n倍，每当时间到了一次服务器发送确认时间间隔，便让对应的条目的time++；
		
		for (int i = 0; i < user_db.size(); i++)
		{
			user_db[i].time++;
			//到了n，检测其是否有发送过确认信息，没有便删除
			if (user_db[i].report == 0 || user_db[i].time == 5)
			{
				char tmp[11];
				strcpy(tmp, user_db[i].sq_pid);
				tmp[10] = 0;
				compare(sq_db, tmp, -1);
				for (int j = 0; j < 12; j++)
				{
					user_db[i].sq_pid[j] = 0;
				}
				flag = 1;
			}
			if (user_db[i].time == 5)
			{
				user_db[i].time == 0;
			}
		}
		//每一次崩溃检测后所有崩溃检测状态初始化
		for (int i = 0; i < user_db.size(); i++)
		{
			user_db[i].report = 0;
		}
		//若条目中主机标识好清0，保存时自动跳过

		if (flag)
		{
			save_user();
			save();
		}
		
	}
	return 0;
}
int task2()
{
	mutex pmt;
	void purchase(SOCKET sock_client);
	
	void save();
	void usage(SOCKET sock_client);
	void confirm(SOCKET sock_client);
	cout << "Start server..." << endl;
	
	WSADATA wsaData;
	WORD sockVersion = MAKEWORD(2, 2);
	if (0 != WSAStartup(sockVersion, &wsaData))
	{
		cout << "Failed to retrive socket version."
			<< endl;
		return 0;
	}
	SOCKET sock_sev;
	sock_sev = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);

	if (INVALID_SOCKET == sock_sev)
	{
		cout << "Invalid socket." << endl;
		WSACleanup();
		
		return 0;
	}
	sockaddr_in addr_sev;
	addr_sev.sin_family = AF_INET;
	addr_sev.sin_port = htons(6666);
	addr_sev.sin_addr.s_addr = INADDR_ANY;
	if (SOCKET_ERROR == bind(sock_sev, (sockaddr*)&addr_sev, sizeof(addr_sev)))
	{
		cout << "Failed to bind." << endl;
		WSACleanup();
		return 0;
	}
	if (SOCKET_ERROR == listen(sock_sev, NUM_CLIENTS))
	{
		cout << "Failed to listen." << endl;
		WSACleanup();
		return 0;
	}

	SOCKET sock_client;
	sockaddr_in addr_client;
	int nAddrLen = sizeof(addr_client);
	while (true)
	{
		
		char tmp[512];
		char* mode;
		sock_client = accept(sock_sev, (sockaddr*)&addr_client, &nAddrLen);
		if (INVALID_SOCKET == sock_client)
		{
			cout << "Failed to accept." << endl;
			continue;
		}
		sprintf(tmp, "Your IP is %s\n\0", inet_ntoa(addr_client.sin_addr));
		cout << "Connection from " << inet_ntoa(addr_client.sin_addr)
			<< endl;
		int recv_size = 0;
		memset(tmp, 0, sizeof(tmp));
		recv_size = recv(sock_client, tmp, 512, 0);
		mode = tmp + 5;
		cout << *mode<<endl;
		if (!strcmp(mode, "Purchase"))
		{
			purchase(sock_client);
			save();
		}
		if (!strcmp(mode, "usage"))
		{
			usage(sock_client);
		}
		if (!strcmp(mode,"Confirm"))
		{
			confirm(sock_client);
		}
		memset(tmp, 0, sizeof(tmp));
		memset(tmp, 0, sizeof(mode));
		
		closesocket(sock_client);
	}
	return 0;
}
// 服务器购买序列号功能，为客户端返回一个可以永久使用的序列号；
char* randstr(char*& str, const int len)
{
	srand(time(NULL));
	int i;
	for (i = 0; i < len; ++i)
	{
		switch ((rand() % 3))
		{
		case 1:
			str[i] = 'A' + rand() % 26;
			break;
		default:
			str[i] = '0' + rand() % 10;
			break;
		}
	}
	str[len-1] = '\0';
	
	return str;
}
void purchase(SOCKET sock_client)
{
	
	void save();
	int compare(vector<sq_list> & a, char* sq,int type);
	purchase_list a;
	char buf[512];
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "110 purchase function ready");
	send(sock_client, buf, strlen(buf), 0);
	int recv_size = 0;
	memset(buf, 0, sizeof(buf));
	recv(sock_client, buf, 512, 0);
	if (*buf == 'U')
	{
		strcpy(a.name, buf + 5);
		cout << buf << endl;
	}
	else
	{
		exit(-1);
	}
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "210 USER READY, Need a pass");
	send(sock_client, buf, strlen(buf), 0);
	memset(buf, 0, sizeof(buf));
	recv(sock_client, buf, 512, 0);
	if (*buf == 'P')
	{
		strcpy(a.pass, buf + 5);
		cout << buf << endl;
	}
	else
	{
		exit(-1);
	}
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "220 PASS READY, Need a TYPE");
	send(sock_client, buf, strlen(buf), 0);
	memset(buf, 0, sizeof(buf));
	recv(sock_client, buf, 512, 0);
	if (*buf == 'T')
	{
		a.type = *(buf + 5);
		cout << buf << endl;
	}
	else
	{
		exit(-1);
	}
	char *sq = new char[11];
	memset(sq, 0, sizeof(sq));
	randstr(sq, 11);
	while (compare(sq_db, sq,0) != 0)
	{
		randstr(sq, 11);
	}
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "230 Seqnum:%s",sq);
	send(sock_client, buf, strlen(buf), 0);
	strcpy(a.sq, sq);
	sq_list f;
	if (a.type == '1')
	{
		f.rest = 10;
	}
	else
	{
		f.rest = 50;
	}
	strcpy(f.sq, sq);
	sq_db.push_back(f);
	save();

	
}
void save()
{
	string path = "data.txt";
	ofstream output = ofstream(path, ios::out | ios::binary);

	for (auto it : sq_db)
	{
		if (it.sq[0] != 0)
		{
			output << it.sq << ',' << it.rest << '\n';
		}
	}
	output.close();

}
void save_user()
{
	string path = "userdata.txt";
	ofstream output = ofstream(path, ios::out | ios::binary);

	for (auto it : user_db)
	{
		if (it.sq_pid[0] != 0)
		{
			output << it.sq_pid << ',' << it.report << '\n';
		}
		
	}
	output.close();
}
int compare(vector<sq_list>& a, char* sq,int type)
{
	for (int i=0;i<a.size();i++)
	{
		if (!strcmp(a[i].sq, sq))
		{
			if (a[i].rest == 0)
			{
				return 2;
			}
			if (type == 1)
			{
				a[i].rest--;
				
			}
			if (type == -1)
			{
				a[i].rest++;
			}
			return 1;
			
		}
	}
	return 0;
}
void confirm(SOCKET sock_client)
{
	void check(char * str);
	int compare(vector<user_list>&a, char* sq, int type);
	char buf[512];
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "130 confirm ready");
	send(sock_client, buf, strlen(buf), 0);
	memset(buf, 0, sizeof(buf));
	recv(sock_client, buf, 512, 0);
	char* sq = new char[13];
	sq = buf + 5;
	if (compare(user_db, sq, 1))
	{
		memset(buf, 0, sizeof(buf));
		sprintf(buf, "250 sqpid confirm");
	}
	else
	{
		memset(buf, 0, sizeof(buf));
		sprintf(buf, "350 invalid sqpid");
	}
	send(sock_client, buf, 512, 0);
	
}
void usage(SOCKET sock_client)
{
	void check(char* str);
	int compare(vector<user_list> &a, char* sq,int type);
	int compare(vector<sq_list> & a, char* sq,int type);
	purchase_list a;
	char buf[512];
	//向客户端确认，可以进行许可证确认
	memset(buf, 0, sizeof(buf));
	sprintf(buf, "120 usage function ready");
	send(sock_client, buf, strlen(buf), 0);
	int recv_size = 0;
	memset(buf, 0, sizeof(buf));
	recv(sock_client, buf, 512, 0);
	char* sq = new char[11];
	sq = buf + 5;
	//验证许可证是否正确，并发送反馈信息
	
	int rest = compare(sq_db, sq,1);
	if (rest==0)
	{
		sprintf(buf, "310 Seqnum wrong");
	}
	else if (rest== 2)
	{
		sprintf(buf, "320 Not usable");
	}
	//若正确，生成10位序列号+两位主机号的正确表示码发送给客户端，进行储存。
	else
	{
		user_list tu;
		memset(tu.sq_pid, 0, sizeof(tu.sq_pid));
		strcpy(tu.sq_pid, sq);
		char* pid = new char[3];
		randstr(pid, 3);
		tu.sq_pid[10] = pid[0];
		tu.sq_pid[11] = pid[1];
		while (compare(user_db, tu.sq_pid,0))
		{
			char *pid=new char[3];
			randstr(pid, 3);
			tu.sq_pid[10] = pid[0];
			tu.sq_pid[11] = pid[1];
			
		}
		
		tu.report = 0;
		tu.time = 0;
		memset(buf, 0, sizeof(buf));
		sprintf(buf, "240 %s",tu.sq_pid);
		user_db.push_back(tu);
		
	}

	send(sock_client, buf, strlen(buf), 0);
	//存储客户端主机唯一标识码信息并更新序列号状态
	save_user();
	save();

}
void setup()
{
	ifstream input = ifstream("data.txt", ios::in);
	sq_list tmp;
	char c;
	while (!input.eof())
	{
		memset(tmp.sq, 0, sizeof(tmp.sq));
		for (int i = 0; i < 10; i++)
		{
			input >> tmp.sq[i];
		}
		input >> c;
		input >> tmp.rest;
		
		sq_db.push_back(tmp);
	}
	
	input.close();
    input = ifstream("userdata.txt", ios::in);
	user_list utmp;
	
	while (!input.eof())
	{
		memset(utmp.sq_pid, 0, sizeof(utmp.sq_pid));
		for (int i = 0; i < 12; i++)
		{
			input >> utmp.sq_pid[i];
		}
		input >> c;
		input >> utmp.report;
		utmp.time = 0;

		user_db.push_back(utmp);
	}

	input.close();
}
bool compare(vector<user_list>&a, char* sq,int type)
{
	for (int i = 0; i < a.size(); i++)
	{
		if (!strcmp(a[i].sq_pid, sq))
		{
			if (type == 1)
			{
				a[i].report++;
			}
			return true;
		}
	}
	return false;
}

